package com.zone.domain.strategy.service.rule.tree.factory.engine.impl;

import com.zone.domain.strategy.model.valobj.RuleActionEnum;
import com.zone.domain.strategy.model.valobj.RuleTreeNodeLineVO;
import com.zone.domain.strategy.model.valobj.RuleTreeNodeVO;
import com.zone.domain.strategy.model.valobj.RuleTreeVO;
import com.zone.domain.strategy.service.rule.tree.ILogicTreeNode;
import com.zone.domain.strategy.service.rule.tree.factory.DefaultTreeNodeFactory;
import com.zone.domain.strategy.service.rule.tree.factory.engine.IDecisionTreeEngine;
import com.zone.types.exception.BizException;
import com.zone.types.utils.CollectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * @author: zongzi
 * @description: 规则树执行引擎，复制树节点的流转，执行各个树节点逻辑
 * @date: 2024/6/11
 */
@Slf4j
public class DefaultDecisionTreeEngine implements IDecisionTreeEngine {
    private final RuleTreeVO ruleTree;
    private final Map<String, ILogicTreeNode> treeNodeHandlerMap;

    public DefaultDecisionTreeEngine(RuleTreeVO ruleTree, Map<String, ILogicTreeNode> treeNodeMap) {
        this.ruleTree = ruleTree;
        this.treeNodeHandlerMap = treeNodeMap;
    }

    @Override
    public DefaultTreeNodeFactory.StrategyAwardVO execute(Long strategyId, String userId, Integer awardId) {
        // 空树不进行处理
        DefaultTreeNodeFactory.StrategyAwardVO strategyAwardVO = DefaultTreeNodeFactory.StrategyAwardVO.builder().awardId(awardId).build();
        if (Objects.isNull(ruleTree) || ruleTree.isEmpty()) {
            return strategyAwardVO;
        }
        // 配置的规则树中的所有ruleKey要存在对应的nodeHandler，nodeHandlerNames >= treeKeys
        Set<String> treeKeys = ruleTree.getTreeNodeMap().keySet();
        Set<String> nodeHandlerNames = treeNodeHandlerMap.keySet();
        if (!nodeHandlerNames.containsAll(treeKeys)) {
            // 不存在处理器的treeKey
            String notHandlerKeys = String.join(",", org.apache.commons.collections4.CollectionUtils.subtract(treeKeys, nodeHandlerNames));
            throw new BizException("规则树配置异常，未查询到的节点处理器：" + notHandlerKeys);
        }

        String ruleKey = ruleTree.getTreeRootNodeKey();
        while (Strings.isNotEmpty(ruleKey)) {
            // 获取树节点ruleKey -> 对用的node Handler
            ILogicTreeNode logicTreeNode = treeNodeHandlerMap.get(ruleKey);
            // 当前树节点配置
            RuleTreeNodeVO currentTreeNode = ruleTree.getNode(ruleKey);
            // 执行树节点操作逻辑
            DefaultTreeNodeFactory.TreeNodeActionEntity treeNodeAction = logicTreeNode.logic(strategyId, userId, awardId, currentTreeNode.getRuleValue());
            strategyAwardVO = treeNodeAction.getStrategyAward();
            RuleActionEnum ruleAction = treeNodeAction.getRuleAction();
            // 判断下一个树节点ruleKey
            ruleKey = nextRuleKey(ruleAction, currentTreeNode.getRuleTreeNodeLineList());
            log.info("tree node handler: {} execute result: {} next tree key: {}", logicTreeNode.getClass().getSimpleName(), treeNodeAction, ruleKey);
        }
        return strategyAwardVO;
    }

    // 获取下一个树节点ruleKey
    private String nextRuleKey(RuleActionEnum ruleAction, List<RuleTreeNodeLineVO> ruleTreeNodeLineList) {
        if (Objects.isNull(ruleAction) || CollectionUtils.isEmpty(ruleTreeNodeLineList)) {
            return null;
        }
        for (RuleTreeNodeLineVO ruleTreeNodeLineVO : ruleTreeNodeLineList) {
            if (this.haveNextRuleKey(ruleAction.getCode(), ruleTreeNodeLineVO)) {
                return ruleTreeNodeLineVO.getRuleNodeTo();
            }
        }
        return null;
    }

    /**
     * 判断是否存在下一个ruleKey
     *
     * @param matchMatter        匹配值
     * @param ruleTreeNodeLineVO 规则树连线
     * @return true/false
     */
    private boolean haveNextRuleKey(String matchMatter, RuleTreeNodeLineVO ruleTreeNodeLineVO) {
        switch (ruleTreeNodeLineVO.getRuleLimitType()) {
            case EQUAL:
                return Objects.equals(ruleTreeNodeLineVO.getRuleLimitValue().getCode(), matchMatter);
            case GT:
            case LT:
            case GE:
            case LE:
            case ENUM:
            default:
                return false;
        }
    }
}
